Программирование сетевых приложений

Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя

Программирование сетевых приложений

Содержание лекции

  • Архитектура «Модель-Представление-Контроллер» (MVC)
  • Создание графического интерфейса при помощи встроенных классов
  • Компоненты и контейнеры
  • Использование элементов управления, менеджеров компоновки и меню
  • Элементы управления
  • Основные понятия
  • Добавление и удаление элементов управления
  • Реагирование на элементы управления
  • Понятие менеджера компоновки
  • Работа с меню и диалоговыми окнами
  • Обработка событий
  • Модель делегирования событий
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

MVC в Qt

Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Model/View Architecture

// Модель - хранит данные
class MyModel : public QAbstractTableModel {
    Q_OBJECT
    
private:
    QList<QPair<QString, int>> data;
    
public:
    int rowCount(const QModelIndex &parent = QModelIndex()) const override {
        return data.size();
    }
    
    int columnCount(const QModelIndex &parent = QModelIndex()) const override {
        return 2;
    }
    
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
        if (!index.isValid() || role != Qt::DisplayRole)
            return QVariant();
            
        if (index.column() == 0)
            return data[index.row()].first;
        else
            return data[index.row()].second;
    }
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Создание базового GUI приложения

#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    
    // Создание главного окна
    QWidget window;
    window.setWindowTitle("Мое первое GUI приложение");
    window.resize(400, 300);
    
    // Создание элементов управления
    QLabel* label = new QLabel("Привет, Qt!");
    QPushButton* button = new QPushButton("Нажми меня");
    
    // Компоновка
    QVBoxLayout* layout = new QVBoxLayout;
    layout->addWidget(label);
    layout->addWidget(button);
    
    window.setLayout(layout);
    window.show();
    
    return app.exec();
}
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Основные классы Qt GUI

Базовые классы окон

Класс Назначение
QWidget Базовый класс всех GUI элементов
QMainWindow Главное окно приложения с меню и панелями инструментов
QDialog Диалоговое окно для взаимодействия с пользователем
QFrame Контейнер с рамкой
QScrollArea Область с полосами прокрутки
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Компоненты и контейнеры

#include <QLineEdit>
#include <QTextEdit>
#include <QComboBox>
#include <QCheckBox>
#include <QRadioButton>
#include <QSlider>
#include <QProgressBar>

class WidgetsExample : public QWidget {
    Q_OBJECT
    
public:
    WidgetsExample(QWidget* parent = nullptr) : QWidget(parent) {
        // Текстовые поля
        QLineEdit* lineEdit = new QLineEdit(this);
        lineEdit->setPlaceholderText("Введите текст...");
        
        QTextEdit* textEdit = new QTextEdit(this);
        textEdit->setPlainText("Многострочный текст");
        
        // Выпадающий список
        QComboBox* comboBox = new QComboBox(this);
        comboBox->addItems({"Вариант 1", "Вариант 2", "Вариант 3"});
        
        // Флажки и переключатели
        QCheckBox* checkBox = new QCheckBox("Согласен", this);
        QRadioButton* radio1 = new QRadioButton("Первый", this);
        QRadioButton* radio2 = new QRadioButton("Второй", this);
    }
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Менеджеры компоновки (Layout Managers)

#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QFormLayout>
#include <QStackedLayout>

class LayoutsExample : public QWidget {
    Q_OBJECT
    
public:
    LayoutsExample(QWidget* parent = nullptr) : QWidget(parent) {
        // Горизонтальная компоновка
        QHBoxLayout* hLayout = new QHBoxLayout;
        hLayout->addWidget(new QPushButton("Кнопка 1"));
        hLayout->addWidget(new QPushButton("Кнопка 2"));
        hLayout->addStretch(); // Растяжка
        
        // Вертикальная компоновка
        QVBoxLayout* vLayout = new QVBoxLayout;
        vLayout->addWidget(new QLabel("Метка"));
        vLayout->addWidget(new QLineEdit);
        vLayout->addSpacing(20); // Промежуток
        vLayout->addLayout(hLayout);
        
        setLayout(vLayout);
    }
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

GridLayout - табличная компоновка

#include <QGridLayout>

class GridLayoutExample : public QWidget {
    Q_OBJECT
    
public:
    GridLayoutExample(QWidget* parent = nullptr) : QWidget(parent) {
        QGridLayout* grid = new QGridLayout;
        
        // Добавление элементов в сетку
        grid->addWidget(new QLabel("Имя:"), 0, 0);
        grid->addWidget(new QLineEdit, 0, 1);
        
        grid->addWidget(new QLabel("Фамилия:"), 1, 0);
        grid->addWidget(new QLineEdit, 1, 1);
        
        grid->addWidget(new QLabel("Возраст:"), 2, 0);
        grid->addWidget(new QSpinBox, 2, 1);
        
        // Объединение ячеек
        QPushButton* okButton = new QPushButton("OK");
        QPushButton* cancelButton = new QPushButton("Отмена");
        
        grid->addWidget(okButton, 3, 0);
        grid->addWidget(cancelButton, 3, 1);
        
        // Установка отступов
        grid->setHorizontalSpacing(10);
        grid->setVerticalSpacing(10);
        grid->setContentsMargins(20, 20, 20, 20);
        
        setLayout(grid);
    }
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

FormLayout - компоновка форм

#include <QFormLayout>

class FormLayoutExample : public QWidget {
    Q_OBJECT
    
public:
    FormLayoutExample(QWidget* parent = nullptr) : QWidget(parent) {
        QFormLayout* formLayout = new QFormLayout;
        
        // Создание полей формы
        QLineEdit* nameEdit = new QLineEdit;
        QLineEdit* emailEdit = new QLineEdit;
        QSpinBox* ageSpinBox = new QSpinBox;
        QComboBox* countryCombo = new QComboBox;
        
        countryCombo->addItems({"Россия", "Беларусь", "Украина", "Казахстан"});
        
        // Добавление строк формы
        formLayout->addRow("Имя:", nameEdit);
        formLayout->addRow("Email:", emailEdit);
        formLayout->addRow("Возраст:", ageSpinBox);
        formLayout->addRow("Страна:", countryCombo);
        
        // Добавление кнопок
        QPushButton* submitButton = new QPushButton("Отправить");
        QPushButton* resetButton = new QPushButton("Сбросить");
        
        QHBoxLayout* buttonLayout = new QHBoxLayout;
        buttonLayout->addWidget(submitButton);
        buttonLayout->addWidget(resetButton);
        
        formLayout->addRow(buttonLayout);
        
        setLayout(formLayout);
        setWindowTitle("Форма регистрации");
    }
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Работа с меню

#include <QMainWindow>
#include <QMenuBar>
#include <QMenu>
#include <QAction>
#include <QStatusBar>

class MainWindow : public QMainWindow {
    Q_OBJECT
    
public:
    MainWindow(QWidget* parent = nullptr) : QMainWindow(parent) {
        createMenuBar();
        createStatusBar();
        setWindowTitle("Приложение с меню");
        resize(800, 600);
    }
    
private:
    void createMenuBar() {
        // Создание меню "Файл"
        QMenu* fileMenu = menuBar()->addMenu("Файл");
        
        // Создание действий
        QAction* newAction = new QAction("Новый", this);
        newAction->setShortcut(QKeySequence::New);
        newAction->setStatusTip("Создать новый файл");
        
        QAction* openAction = new QAction("Открыть...", this);
        openAction->setShortcut(QKeySequence::Open);
        
        QAction* saveAction = new QAction("Сохранить", this);
        saveAction->setShortcut(QKeySequence::Save);
        
        QAction* exitAction = new QAction("Выход", this);
        exitAction->setShortcut(QKeySequence::Quit);
        
        // Добавление действий в меню
        fileMenu->addAction(newAction);
        fileMenu->addAction(openAction);
        fileMenu->addAction(saveAction);
        fileMenu->addSeparator();
        fileMenu->addAction(exitAction);
        
        // Подключение сигналов
        connect(exitAction, &QAction::triggered, this, &QMainWindow::close);
    }
    
    void createStatusBar() {
        statusBar()->showMessage("Готово");
    }
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Панели инструментов и панели состояния

#include <QToolBar>
#include <QStatusBar>
#include <QIcon>

class ToolbarExample : public QMainWindow {
    Q_OBJECT
    
public:
    ToolbarExample(QWidget* parent = nullptr) : QMainWindow(parent) {
        // Создание панели инструментов
        QToolBar* fileToolbar = addToolBar("Файл");
        
        // Добавление действий на панель инструментов
        QAction* newAction = new QAction(QIcon(":/icons/new.png"), "Новый", this);
        QAction* openAction = new QAction(QIcon(":/icons/open.png"), "Открыть", this);
        QAction* saveAction = new QAction(QIcon(":/icons/save.png"), "Сохранить", this);
        
        fileToolbar->addAction(newAction);
        fileToolbar->addAction(openAction);
        fileToolbar->addAction(saveAction);
        fileToolbar->addSeparator();
        
        // Кнопка с выпадающим меню
        QToolButton* toolButton = new QToolButton(this);
        toolButton->setText("Инструменты");
        toolButton->setPopupMode(QToolButton::MenuButtonPopup);
        
        QMenu* toolMenu = new QMenu(this);
        toolMenu->addAction("Инструмент 1");
        toolMenu->addAction("Инструмент 2");
        toolButton->setMenu(toolMenu);
        
        fileToolbar->addWidget(toolButton);
        
        // Статус бар
        statusBar()->showMessage("Приложение запущено");
        
        // Добавление перманентного виджета в статус бар
        QLabel* permanentLabel = new QLabel("Готов");
        statusBar()->addPermanentWidget(permanentLabel);
    }
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Диалоговые окна

#include <QMessageBox>
#include <QFileDialog>
#include <QInputDialog>
#include <QColorDialog>
#include <QFontDialog>

class DialogsExample : public QWidget {
    Q_OBJECT
    
public slots:
    void showMessageBox() {
        // Информационное сообщение
        QMessageBox::information(this, "Информация", 
                                "Операция выполнена успешно!");
        
        // Вопрос с выбором
        int reply = QMessageBox::question(this, "Подтверждение",
                                        "Вы уверены, что хотите удалить?",
                                        QMessageBox::Yes | QMessageBox::No);
        
        if (reply == QMessageBox::Yes) {
            // Действие при подтверждении
        }
    }
    
    void showFileDialog() {
        // Диалог открытия файла
        QString fileName = QFileDialog::getOpenFileName(
            this,
            "Открыть файл",
            "",
            "Текстовые файлы (*.txt);;Все файлы (*.*)"
        );
        
        if (!fileName.isEmpty()) {
            // Работа с файлом
        }
    }
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Пользовательские диалоговые окна

#include <QDialog>
#include <QDialogButtonBox>

class CustomDialog : public QDialog {
    Q_OBJECT
    
private:
    QLineEdit* nameEdit;
    QSpinBox* ageSpinBox;
    QCheckBox* agreeCheckBox;
    
public:
    CustomDialog(QWidget* parent = nullptr) : QDialog(parent) {
        setWindowTitle("Пользовательский диалог");
        setModal(true);
        resize(300, 200);
        
        // Создание элементов
        nameEdit = new QLineEdit;
        ageSpinBox = new QSpinBox;
        ageSpinBox->setRange(1, 120);
        agreeCheckBox = new QCheckBox("Я согласен с условиями");
        
        // Создание кнопок
        QDialogButtonBox* buttonBox = new QDialogButtonBox(
            QDialogButtonBox::Ok | QDialogButtonBox::Cancel
        );
        
        // Подключение сигналов
        connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
        connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
        
        // Компоновка
        QFormLayout* layout = new QFormLayout;
        layout->addRow("Имя:", nameEdit);
        layout->addRow("Возраст:", ageSpinBox);
        layout->addRow(agreeCheckBox);
        layout->addRow(buttonBox);
        
        setLayout(layout);
    }
    
    QString getName() const { return nameEdit->text(); }
    int getAge() const { return ageSpinBox->value(); }
    bool isAgreed() const { return agreeCheckBox->isChecked(); }
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Обработка событий - Сигналы и слоты

#include <QObject>
#include <QDebug>

class EventHandler : public QObject {
    Q_OBJECT
    
public slots:
    void handleButtonClicked() {
        qDebug() << "Кнопка нажата!";
    }
    
    void handleTextChanged(const QString& text) {
        qDebug() << "Текст изменен:" << text;
    }
    
    void handleValueChanged(int value) {
        qDebug() << "Значение изменено:" << value;
    }
};

// Использование
class WidgetExample : public QWidget {
    Q_OBJECT
    
public:
    WidgetExample(QWidget* parent = nullptr) : QWidget(parent) {
        QPushButton* button = new QPushButton("Нажми меня", this);
        QLineEdit* lineEdit = new QLineEdit(this);
        QSlider* slider = new QSlider(Qt::Horizontal, this);
        
        EventHandler* handler = new EventHandler(this);
        
        // Подключение сигналов к слотам
        connect(button, &QPushButton::clicked, 
                handler, &EventHandler::handleButtonClicked);
        
        connect(lineEdit, &QLineEdit::textChanged,
                handler, &EventHandler::handleTextChanged);
        
        connect(slider, &QSlider::valueChanged,
                handler, &EventHandler::handleValueChanged);
    }
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Пользовательские события

#include <QEvent>
#include <QMouseEvent>
#include <QKeyEvent>

class CustomWidget : public QWidget {
    Q_OBJECT
    
protected:
    // Обработка событий мыши
    void mousePressEvent(QMouseEvent* event) override {
        if (event->button() == Qt::LeftButton) {
            qDebug() << "Левая кнопка мыши нажата в точке:" 
                     << event->pos();
        }
    }
    
    void mouseMoveEvent(QMouseEvent* event) override {
        qDebug() << "Мышь перемещена в точку:" << event->pos();
    }
    
    void mouseReleaseEvent(QMouseEvent* event) override {
        qDebug() << "Кнопка мыши отпущена";
    }
    
    // Обработка событий клавиатуры
    void keyPressEvent(QKeyEvent* event) override {
        qDebug() << "Клавиша нажата:" << event->key()
                 << "Текст:" << event->text();
        
        if (event->key() == Qt::Key_Escape) {
            close();
        }
    }
    
    void keyReleaseEvent(QKeyEvent* event) override {
        qDebug() << "Клавиша отпущена:" << event->key();
    }
    
    // Обработка событий изменения размера
    void resizeEvent(QResizeEvent* event) override {
        qDebug() << "Размер изменен с" << event->oldSize()
                 << "на" << event->size();
    }
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Фильтры событий

#include <QEvent>
#include <QObject>

class EventFilter : public QObject {
    Q_OBJECT
    
protected:
    bool eventFilter(QObject* obj, QEvent* event) override {
        if (event->type() == QEvent::KeyPress) {
            QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
            qDebug() << "Фильтр: нажата клавиша" << keyEvent->key()
                     << "в объекте" << obj->objectName();
            
            // Блокировка нажатия клавиши Enter
            if (keyEvent->key() == Qt::Key_Return) {
                return true; // Событие обработано, дальше не передавать
            }
        }
        
        // Стандартная обработка
        return QObject::eventFilter(obj, event);
    }
};

// Установка фильтра
class FilterExample : public QWidget {
    Q_OBJECT
    
public:
    FilterExample(QWidget* parent = nullptr) : QWidget(parent) {
        QLineEdit* lineEdit1 = new QLineEdit(this);
        QLineEdit* lineEdit2 = new QLineEdit(this);
        
        lineEdit1->setObjectName("lineEdit1");
        lineEdit2->setObjectName("lineEdit2");
        
        EventFilter* filter = new EventFilter(this);
        
        // Установка фильтра для виджетов
        lineEdit1->installEventFilter(filter);
        lineEdit2->installEventFilter(filter);
    }
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Пользовательские события и сигналы

#include <QEvent>
#include <QCoreApplication>

// Определение пользовательского типа события
const QEvent::Type CustomEventType = static_cast<QEvent::Type>(QEvent::User + 1);

class CustomEvent : public QEvent {
private:
    QString message;
    int priority;
    
public:
    CustomEvent(const QString& msg, int prio) 
        : QEvent(CustomEventType), message(msg), priority(prio) {}
    
    QString getMessage() const { return message; }
    int getPriority() const { return priority; }
};

class CustomEventWidget : public QWidget {
    Q_OBJECT
    
signals:
    void customSignal(const QString& message, int value);
    
public:
    CustomEventWidget(QWidget* parent = nullptr) : QWidget(parent) {}
    
    // Отправка пользовательского события
    void sendCustomEvent(const QString& message, int priority) {
        CustomEvent* event = new CustomEvent(message, priority);
        QCoreApplication::postEvent(this, event);
    }
    
protected:
    // Обработка пользовательского события
    void customEvent(QEvent* event) override {
        if (event->type() == CustomEventType) {
            CustomEvent* customEvent = static_cast<CustomEvent*>(event);
            qDebug() << "Пользовательское событие:"
                     << customEvent->getMessage()
                     << "Приоритет:" << customEvent->getPriority();
            
            // Генерация сигнала
            emit customSignal(customEvent->getMessage(), 
                            customEvent->getPriority());
        }
    }
};
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Современные подходы к GUI разработке

QML и Qt Quick

// main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[]) {
    QGuiApplication app(argc, argv);
    
    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    
    if (engine.rootObjects().isEmpty())
        return -1;
    
    return app.exec();
}
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

QML разметка (main.qml)

import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    id: window
    visible: true
    width: 640
    height: 480
    title: qsTr("Современный GUI на QML")
    
    Rectangle {
        anchors.fill: parent
        gradient: Gradient {
            GradientStop { position: 0.0; color: "#1e3c72" }
            GradientStop { position: 1.0; color: "#2a5298" }
        }
        
        Column {
            anchors.centerIn: parent
            spacing: 20
            
            Text {
                text: qsTr("Добро пожаловать в Qt Quick!")
                font.pixelSize: 24
                color: "white"
                anchors.horizontalCenter: parent.horizontalCenter
            }
            
            Button {
                text: qsTr("Нажми меня")
                anchors.horizontalCenter: parent.horizontalCenter
                onClicked: {
                    console.log("Кнопка нажата!")
                }
            }
        }
    }
}
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Лучшие практики GUI разработки

1. Архитектурные принципы

  • Разделение ответственности - используйте MVC/MVP
  • Минимизация зависимостей - слабая связанность компонентов
  • Повторное использование - создавайте переиспользуемые компоненты
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

2. Производительность

// Использование setUpdatesEnabled для групповых обновлений
void updateMultipleWidgets() {
    setUpdatesEnabled(false);
    
    // Множественные изменения
    label1->setText("Новый текст 1");
    label2->setText("Новый текст 2");
    progressBar->setValue(50);
    
    setUpdatesEnabled(true);
}
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

3. Пользовательский опыт

  • Отзывчивый интерфейс - используйте потоки для длительных операций
  • Интуитивность - следуйте стандартам интерфейса
  • Доступность - учитывайте пользователей с ограниченными возможностями
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Резюме

Ключевые концепции

  • Архитектура MVC - основа организации GUI приложений
  • Сигналы и слоты - механизм взаимодействия компонентов
  • Менеджеры компоновки - автоматическое размещение элементов
  • Обработка событий - реакция на действия пользователя
  • Диалоговые окна - взаимодействие с пользователем
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Инструменты Qt для GUI

  • QWidget - базовый класс всех элементов интерфейса
  • QLayout - система компоновки
  • QMainWindow - главное окно приложения
  • QDialog - диалоговые окна
  • Сигналы и слоты - механизм обработки событий
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Дальнейшее изучение

  • QML и Qt Quick - современные технологии GUI
  • Анимации и переходы - улучшение пользовательского опыта
  • Кастомные виджеты - создание уникальных компонентов
  • Интернационализация - поддержка многоязычности
  • Тестирование GUI - автоматизированное тестирование интерфейса
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя
Программирование сетевых приложений

Вопросы для самопроверки

  1. Что такое архитектура MVC и как она реализована в Qt?
  2. Какие существуют типы менеджеров компоновки и когда их использовать?
  3. Как подключить обработчик события к кнопке?
  4. Чем отличается QMainWindow от QDialog?
  5. Как создать пользовательское событие и обработать его?
  6. Какие существуют стандартные диалоговые окна в Qt?
  7. Как реализовать фильтрацию событий?
  8. Что такое сигналы и слоты в Qt?
  9. Как создать меню и панель инструментов?
  10. Какие лучшие практики следует учитывать при разработке GUI?
Библиотеки и средства внедрения визуальных компонент для организации GUI-интерфейсов пользователя

Заметки докладчика: - GUI — обязательная часть клиентских сетевых приложений (мессенджеры, почтовые клиенты, FTP-клиенты и т.д.) - В данной лекции рассматривается подход Qt Widgets (классический, на C++) - Qt Quick/QML представлен кратко как современная альтернатива — декларативный язык для описания UI - Лабораторная работа: создать GUI для мессенджера — прямая связь с лекцией 11 (RPC, удалённые вызовы) - Для сетевых приложений критически важно: GUI не должен блокировать сетевые операции (используем потоки и асинхронные сигналы/слоты)

Заметки докладчика: - Каждый Qt GUI-приложение должен иметь ровно один объект QApplication (или QGuiApplication для QML) - QWidget — базовый класс для всех визуальных элементов (кнопки, метки, окна — всё наследуется от QWidget) - Способы создания UI в Qt: 1) программно (наш подход в лекции), 2) в Qt Designer (.ui файлы, конвертируемые в код), 3) в QML (декларативно) - app.exec() запускает главный цикл обработки событий (event loop) — это блокирующий вызов - Для сетевых приложений: QApplication также обрабатывает события от сокетов через event loop (QSocketNotifier)

Заметки докладчика: - НИКОГДА не используйте абсолютное позиционирование (setGeometry, move) в реальных проектах — элементы «сломаются» при изменении размера окна - Менеджеры компоновки автоматически обрабатывают изменение размеров, разные разрешения экрана, локализацию (разную длину текста) - QVBoxLayout — вертикальный стек (виджеты сверху вниз), QHBoxLayout — горизонтальный ряд (слева направо), QGridLayout — табличная сетка - Компоновки можно вкладывать друг в друга для создания сложных интерфейсов (например, QHBoxLayout внутри QVBoxLayout) - addStretch() добавляет «пружину» — растяжимое пустое пространство

Заметки докладчика: - Сигналы и слоты — механизм Qt для обработки событий (альтернатива колбэкам/слушателям в других фреймворках) - Ключевое преимущество: типобезопасность (проверка на этапе компиляции), работа между потоками (queued connection) - Новый синтаксис: connect(sender, &Sender::signal, receiver, &Receiver::slot) — предпочтительный - Для сетевых приложений: сигнал readyRead() сокета подключается к слоту обработки данных — это основа асинхронного сетевого ввода-вывода в Qt - Сигнал может быть подключён к нескольким слотам, слот — к нескольким сигналам - Lambda-функции можно использовать как слоты: connect(button, &QPushButton::clicked, [](){ ... });

Заметки докладчика: - В Qt события доставляются через метод QObject::event() — это точка входа для всех событий - Для стандартных событий переопределяйте конкретные обработчики: mousePressEvent, keyPressEvent, resizeEvent и т.д. - Для нестандартных событий переопределяйте event() и проверяйте тип через event->type() - Фильтры событий (eventFilter) позволяют перехватывать события других объектов — полезно для валидации ввода - Для сетевых приложений: QNetworkAccessManager генерирует сигналы (finished(), readyRead()), а не события мыши/клавиатуры — это другой механизм взаимодействия

Заметки докладчика: - QML — декларативный язык (синтаксис, похожий на JSON) для описания UI - Отделяет дизайн интерфейса от логики на C++ — дизайнер может работать в Qt Design Studio - Подходит для быстрого прототипирования и мобильных/встроенных приложений - Взаимодействие C++ и QML через Q_PROPERTY и зарегистрированные типы (qmlRegisterType) - Для данного курса QML не является обязательным, но полезно знать о его существовании как альтернативе - Qt Quick использует GPU-ускоренный рендеринг (Scene Graph) — лучше для анимаций

Заметки докладчика: Ожидаемые ответы на вопросы самопроверки: 1. MVC разделяет данные (Model), отображение (View) и логику (Controller). В Qt — Model/View/Delegate (MVD): QAbstractItemModel + QListView + QStyledItemDelegate. 2. QVBoxLayout (вертикальный стек), QHBoxLayout (горизонтальный ряд), QGridLayout (таблица), QFormLayout (форма «метка — поле»), QStackedLayout (переключаемые страницы). QVBoxLayout/HLayout — для простых случаев, QGridLayout — для табличных данных, QFormLayout — для форм ввода. 3. Через механизм сигналов и слотов: connect(button, &QPushButton::clicked, this, &MyClass::onClicked). Также можно подключить к лямбде: connect(button, &QPushButton::clicked, [](){ ... }). 4. QMainWindow — главное окно приложения с меню, панелями инструментов и статус-баром. QDialog — модальное/немодальное диалоговое окно для взаимодействия с пользователем (ввод данных, подтверждения). 5. Определить тип события (QEvent::User + N), создать класс-наследник QEvent, отправить через QCoreApplication::postEvent(), обработать в customEvent(). 6. QMessageBox (информация, предупреждение, вопрос), QFileDialog (открытие/сохранение файлов), QInputDialog (ввод текста/числа), QColorDialog (выбор цвета), QFontDialog (выбор шрифта). 7. Наследовать QObject, переопределить eventFilter(), вызвать installEventFilter() на целевом объекте. Возвращать true — событие перехвачено, false — передать дальше. 8. Сигнал — объявление события (signals:), слот — обработчик (public slots:/private slots:). Связываются через connect(). Работают между потоками (queued connection). Типобезопасны. 9. Через QMenuBar: menuBar()->addMenu("Файл"), добавить QAction с помощью addAction(). Панель инструментов: addToolBar("Имя"), addAction() на панель. QAction может быть общим для меню и панели инструментов. 10. Использовать менеджеры компоновки (не абсолютное позиционирование), разделять логику и UI (MVC), не блокировать GUI-поток (длительные операции в отдельных потоках), использовать setUpdatesEnabled для групповых обновлений, соблюдать стандарты платформы.